﻿using System;
using System.Collections.Generic;

namespace NetworkLib.Utilities
{
    public abstract class DataByteArray
    {
        public delegate T ByteArrayReadDelegate<T>(ByteArray data);

        public delegate void ByteArrayWriteDelegate<T>(ByteArray data, T obj);

        public DataByteArray() { }

        public abstract void Read(ByteArray byteArray);

        public abstract void Write(ByteArray byteArray);

        #region internal

        public static T FromByteArray<T>(ByteArray byteArray) where T : DataByteArray
        {
            var item = Activator.CreateInstance<T>();
            item.Read(byteArray);
            return item;
        }

        #endregion

        #region array

        public static T[] ReadArray<T>(ByteArray byteArray) where T : DataByteArray
        {
            int count = byteArray.ReadInt();
            var array = new T[count];
            for (int i = 0; i < count; i++)
            {
                array[i] = FromByteArray<T>(byteArray);
            }
            return array;
        }

        public static void WriteArray<T>(T[] array, ByteArray byteArray) where T : DataByteArray
        {
            byteArray.WriteInt(array.Length);
            foreach (T item in array)
            {
                item.Write(byteArray);
            }
        }

        public static T[] ReadArray<T>(ByteArray byteArray, ByteArrayReadDelegate<T> fun)
        {
            int count = byteArray.ReadInt();
            var array = new T[count];
            for (int i = 0; i < count; i++)
            {
                array[i] = fun(byteArray);
            }
            return array;
        }

        public static void WriteArray<T>(T[] list, ByteArray byteArray, ByteArrayWriteDelegate<T> sub)
        {
            byteArray.WriteInt(list.Length);
            foreach (T item in list)
            {
                sub(byteArray, item);
            }
        }

        #endregion

        #region list

        public static List<T> ReadList<T>(ByteArray byteArray) where T : DataByteArray
        {
            int count = byteArray.ReadInt();
            var list = new List<T>(count);
            for (int i = 0; i < count; i++)
            {
                var item = FromByteArray<T>(byteArray);
                list.Add(item);
            }
            return list;
        }

        public static void WriteList<T>(List<T> list, ByteArray byteArray) where T : DataByteArray
        {
            byteArray.WriteInt(list.Count);
            foreach (T item in list)
            {
                item.Write(byteArray);
            }
        }

        public static List<T> ReadList<T>(ByteArray byteArray, ByteArrayReadDelegate<T> fun)
        {
            int count = byteArray.ReadInt();
            var list = new List<T>(count);
            for (int i = 0; i < count; i++)
            {
                var item = fun(byteArray);
                list.Add(item);
            }
            return list;
        }

        public static void WriteList<T>(List<T> list, ByteArray byteArray, ByteArrayWriteDelegate<T> sub)
        {
            byteArray.WriteInt(list.Count);
            foreach (T item in list)
            {
                sub(byteArray, item);
            }
        }

        #endregion

        public static void ByteArrayWrite(ByteArray byteArray, object value)
        {
            if (value == null)
            {
                return;
            }
            else if (value is string)
            {
                byteArray.WriteUTF((string)value);
            }
            else if (value is byte)
            {
                byteArray.WriteByte((byte)value);
            }
            else if (value is short)
            {
                byteArray.WriteShort((short)value);
            }
            else if (value is int)
            {
                byteArray.WriteInt((int)value);
            }
            else if (value is bool)
            {
                byteArray.WriteBoolean((bool)value);
            }
            else if (value is DataByteArray)
            {
                ((DataByteArray)value).Write(byteArray);
            }
            //else
            //{

            //}
        }
    }
}
